﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using Lib.Helper;
using MSIACCSL2.Command;
using MSIACCSL2.MenuServices;
using MSIACCSL2.RoleServices;
using MSIACCSL2.Views.Role;
using WcfService1.DTO;
using GetListByCriteriaCompletedEventArgs = MSIACCSL2.RoleServices.GetListByCriteriaCompletedEventArgs;
using GetListCompletedEventArgs = MSIACCSL2.RoleServices.GetListCompletedEventArgs;
using SaveCompletedEventArgs = MSIACCSL2.RoleServices.SaveCompletedEventArgs;

namespace MSIACCSL2.ViewModels
{
    public class RoleViewModel : ViewModelBase
    {
        #region Delegates

        public delegate void Completed(Object param);

        #endregion

        private static string OrderType;
        private static string PropertySort;
        public static Mode mode;
        private static RoleDTO _Role;
        private static Add frmAdd;
        public static Completed OnSearchCompleted;
        private readonly MenuServicesClient MenuClient;
        private readonly RoleServicesClient client;
        private int CurrentPage;
        private ObservableCollection<int> Pages;
        private bool _IsBusy;
        private PagedCollectionView _Roles;
        private List<string> _errors;
        private ObservableCollection<MenuDTO> _menus;
        private Visibility _messageVisibility;
        private PagedCollectionView _pageSources;
        private Search frmSearch;
        private ValidationHandler validationHandler;


        public RoleViewModel()
        {
            if (!DesignerProperties.IsInDesignTool)
            {
                client = new RoleServicesClient();
                MenuClient = new MenuServicesClient();
                OnPageChanged = new DelegateCommand(PageIndexChanged, CanPageIndexChanged);
                Save = new DelegateCommand(SaveRole, CanSave);
                New = new DelegateCommand(NewRole, CanNew);
                Edit = new DelegateCommand(EditRole, CanEdit);
                Unload = new DelegateCommand(Release, CanUnload);
                SearchCommand = new DelegateCommand(SearchRole, CanSearch);
                SearchResultCommand = new DelegateCommand(SearchResult, CanSearchResult);
                validationHandler = new ValidationHandler();
                MessageVisibility = Visibility.Collapsed;


                if (mode == Mode.Edit || mode == Mode.Search || mode == Mode.Add)
                {
                    GetMenus();
                }
                else
                {
                    GetList(1, null);
                }
            }
        }

        public PagedCollectionView Roles
        {
            get { return _Roles; }

            private set
            {
                if (Roles == value) return;
                _Roles = value;

                int i = (CurrentPage*30);
                foreach (object Role in Roles)
                {
                    i += 1;

                    ((RoleDTO) Role).No = i;
                }

                FirePropertyChanged("Roles");
                Roles.CollectionChanged += Role_CollectionChanged;
            }
        }


        public PagedCollectionView PageSources
        {
            get { return _pageSources; }
            private set
            {
                if (PageSources == value) return;
                _pageSources = value;
                FirePropertyChanged("PageSources");
            }
        }


        public bool IsBusy
        {
            get { return _IsBusy; }
            internal set
            {
                _IsBusy = value;
                FirePropertyChanged("IsBusy");
            }
        }


        public long RecordCount { get; set; }

        //Buat binding ke child form waktu mau edit
        public static RoleDTO Role
        {
            get { return _Role; }
            private set
            {
                if (Role == value) return;
                _Role = value;
                FirePropertyChanged2("Role");
            }
        }

        public ObservableCollection<MenuDTO> Menus
        {
            get { return _menus; }
            private set
            {
                if (Menus == value) return;
                _menus = value;
                FirePropertyChanged("Menus");
            }
        }


        public ICommand OnPageChanged { get; set; }
        public ICommand Save { get; set; }
        public ICommand New { get; set; }
        public ICommand Edit { get; set; }
        public ICommand Unload { get; set; }
        public ICommand SearchCommand { get; set; }
        public ICommand SearchResultCommand { get; set; }

        public List<string> Errors
        {
            get { return _errors; }
            private set
            {
                if (Errors == value) return;
                _errors = value;
                FirePropertyChanged("Errors");
            }
        }

        public Visibility MessageVisibility
        {
            get { return _messageVisibility; }
            private set
            {
                if (MessageVisibility == value) return;
                _messageVisibility = value;
                FirePropertyChanged("MessageVisibility");
            }
        }

        public void Complete(Object param)
        {
            OnSearchCompleted(param);
        }

        private void Role_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (((PagedCollectionView) sender).SortDescriptions.Count > 0)
            {
                if (((PagedCollectionView) sender).SortDescriptions[0].PropertyName.ToLower() == "no") return;

                PropertySort = ((PagedCollectionView) sender).SortDescriptions[0].PropertyName;
                if (string.IsNullOrEmpty(OrderType))
                {
                    OrderType = "ASC";
                }
                else
                {
                    OrderType = OrderType == "ASC" ? OrderType = "DESC" : OrderType = "ASC";
                }
                GetList(1, PropertySort);
            }
        }


        public void SaveRole(Object role)
        {
            Role = (RoleDTO) role;
            Validate();
            if (Errors.Count > 0) return;
            MapMenuToCurrentRole();
            if (string.IsNullOrEmpty(Role.RoleId)) Role.RoleId = Guid.NewGuid().ToString();
            Role.created_by = GlobalVar.User.UserID;
            Role.modified_by = GlobalVar.User.UserID;
            client.SaveCompleted += client_SaveRoleCompleted;
            client.SaveAsync(Role);
        }

        private void MapMenuToCurrentRole()
        {
            Role.Menus = new ObservableCollection<MenuDTO>();
            foreach (MenuDTO menu in Menus)
            {
                if (menu.IsSelected) Role.Menus.Add(menu);
                MapSubMenu(menu);
            }
        }

        private void MapSubMenu(MenuDTO menu)
        {
            if (menu.SubMenus == null) return;
            foreach (MenuDTO subMenu in menu.SubMenus)
            {
                if (subMenu.IsSelected) Role.Menus.Add(subMenu);
                MapSubMenu(subMenu);
            }
        }

        private void client_SaveRoleCompleted(object sender, SaveCompletedEventArgs e)
        {
            if (e.Error != null) Validate(e.Error.ToString());
            client.SaveCompleted -= client_SaveRoleCompleted;
            if (e.Result)
            {
                MessageBox.Show("Success");
                frmAdd.DialogResult = true;
                Refresh();
            }
        }


        public void GetList(int? page, string sortProp)
        {
            IsBusy = true;
            client.GetListCompleted += client_GetListCompleted;
            client.GetListAsync(page ?? 1, sortProp, OrderType);
        }

        private void client_GetListCompleted(object sender, GetListCompletedEventArgs e)
        {
            RecordCount = e.recordCount;
            if (PageSources == null) CreatePageNumber();
            client.GetListCompleted -= client_GetListCompleted;
            Roles = new PagedCollectionView(e.Result);
            IsBusy = false;
            Complete(this);
        }

        public void GetMenus()
        {
            MenuClient.GetAllMenuCompleted += MenuClient_GetAllMenuCompleted;
            MenuClient.GetAllMenuAsync();
        }

        private void MenuClient_GetAllMenuCompleted(object sender, GetAllMenuCompletedEventArgs e)
        {
            MenuClient.GetAllMenuCompleted -= MenuClient_GetAllMenuCompleted;
            var menus = new ObservableCollection<MenuDTO>();
            foreach (MenuDTO menuDto in e.Result)
            {
                menus.Add(MapMenu(menuDto));
            }
            BuildMenu(menus);
        }


        private void NewRole(Object param)
        {
            mode = Mode.Add;
            Role = new RoleDTO();
            frmAdd = new Add();
            frmAdd.Show();
        }


        public static void EditRole(Object param)
        {
            mode = Mode.Edit;
            Role = (RoleDTO) param;
            frmAdd = new Add();
            frmAdd.Show();
        }


        private void SearchRole(Object param)
        {
            mode = Mode.Search;
            frmSearch = new Search();
            frmSearch.Show();
        }


        private void SearchResult(Object param)
        {
            //Dictionary<String, Object> criteria = new Dictionary<string, object>();
            //frmSearch = (Search)param;
            //if (!String.IsNullOrEmpty(frmSearch.txtRoleName.Text)) criteria.Add("RoleName", frmSearch.txtRoleName.Text);
            //if (!String.IsNullOrEmpty(frmSearch.txtNamaLengkap.Text)) criteria.Add("NamaLengkap", frmSearch.txtNamaLengkap.Text);
            //if (!String.IsNullOrEmpty(frmSearch.txtEmail.Text)) criteria.Add("Email", frmSearch.txtEmail.Text);
            //if (!String.IsNullOrEmpty(frmSearch.txtTelp.Text)) criteria.Add("hpp_awal", frmSearch.txtTelp.Text);
            //string expression = string.Empty;
            //if (frmSearch.rblOr.IsChecked ?? false) expression = "OR"; else expression = "AND";
            //RoleSearch(criteria, expression);
        }

        private void RoleSearch(Dictionary<String, Object> criteria, string expression)
        {
            frmSearch.DialogResult = true;
            IsBusy = true;
            Complete(this);
            client.GetListByCriteriaCompleted += client_GetListByCriteriaCompleted;
            client.GetListByCriteriaAsync(criteria, expression, 1);
        }

        private void client_GetListByCriteriaCompleted(object sender, GetListByCriteriaCompletedEventArgs e)
        {
            client.GetListByCriteriaCompleted -= client_GetListByCriteriaCompleted;
            Roles = new PagedCollectionView(e.Result);
            RecordCount = e.recordCount;
            CreatePageNumber();
            IsBusy = false;
        }


        private void CreatePageNumber()
        {
            Pages = new ObservableCollection<int>();
            for (int i = 0; i < RecordCount; i++)
            {
                Pages.Add(i);
            }
            PageSources = new PagedCollectionView(Pages);
        }


        private void PageIndexChanged(Object pageIndex)
        {
            //Jika Pertama kali jangan di Getlagi
            Role = null;
            if (Roles != null && CurrentPage != (int) pageIndex)
            {
                CurrentPage = (int) pageIndex;
                if (String.IsNullOrEmpty(PropertySort))
                    GetList((int) pageIndex + 1, null);
                else GetList((int) pageIndex + 1, PropertySort);
            }
        }


        public bool CanPageIndexChanged(Object param)
        {
            return true;
        }


        public bool CanSave(Object param)
        {
            return true;
        }


        public bool CanNew(Object param)
        {
            return true;
        }

        public bool CanEdit(Object param)
        {
            return true;
        }


        public bool CanUnload(Object param)
        {
            return true;
        }


        public bool CanSearch(Object param)
        {
            return true;
        }

        public bool CanSearchResult(Object param)
        {
            return true;
        }


        public void Release(Object param)
        {
            param = null;
            Role = null;
            OrderType = null;
            PropertySort = null;
            mode = Mode.Idle;
        }


        public void Refresh()
        {
            if (Roles == null)
                GetList(1, null);
            else
                Complete(this);
        }


        public void Validate(string error = null)
        {
            Errors = new List<string>();
            if (string.IsNullOrEmpty(Role.RoleName))
                Errors.Add("Rolename tidak boleh kurang dari 3 karakter");

            if (!string.IsNullOrEmpty(error))
                Errors.Add(error);

            if (Errors.Count > 0)
            {
                MessageVisibility = Visibility.Visible;
            }
            else
            {
                MessageVisibility = Visibility.Collapsed;
            }
        }


        private MenuDTO MapMenu(MenuDTO menuDTO)
        {
            var menu = new MenuDTO();
            menu.Description = menuDTO.Description;
            menu.MenuID = menuDTO.MenuID;
            menu.MenuText = menuDTO.MenuText;
            menu.Number = menuDTO.Number;
            menu.URL = menuDTO.URL;
            if (menuDTO.ParentMenu != null)
                menu.ParentMenu = MapMenu(menuDTO.ParentMenu);
            //sekalian cek apakah menu ini ada di current role kalo ada flag isSelected
            if (Role.Menus != null && Role.Menus.Any(x => x.MenuID == menu.MenuID))
                menu.IsSelected = true;

            return menu;
        }

        private void BuildMenu(ObservableCollection<MenuDTO> menus)
        {
            Menus = new ObservableCollection<MenuDTO>();
            foreach (MenuDTO parent in menus.Where(m => m.ParentMenu == null))
            {
                Menus.Add(parent);
                BuildSubMenu(parent, menus);
            }
        }


        private void BuildSubMenu(MenuDTO parent, ObservableCollection<MenuDTO> menus)
        {
            foreach (MenuDTO menu in menus.Where(m => m.ParentMenu != null && m.ParentMenu.MenuID == parent.MenuID))
            {
                if (parent.SubMenus == null) parent.SubMenus = new ObservableCollection<MenuDTO>();
                {
                    parent.SubMenus.Add(menu);
                    BuildSubMenu(menu, menus);
                }
            }
        }
    }


    public class RoleWrapViewModel : ViewModelBase
    {
        private readonly RoleServicesClient client;

        public RoleWrapViewModel()
        {
            if (!DesignerProperties.IsInDesignTool)
            {
                EditCommand = new DelegateCommand(Edit, CanEditCommand);
                DeleteCommand = new DelegateCommand(Delete, CanDeleteCommand);
                client = new RoleServicesClient();
            }
        }


        public ICommand EditCommand { get; set; }
        public ICommand DeleteCommand { get; set; }


        public bool CanEditCommand(Object param)
        {
            return true;
        }

        public bool CanDeleteCommand(Object param)
        {
            return true;
        }


        public void Edit(Object param)
        {
            RoleViewModel.EditRole(param);
        }

        public void Delete(Object param)
        {
            client.DeleteCompleted += client_DeleteCompleted;
            client.DeleteAsync((RoleDTO) param);
        }

        private void client_DeleteCompleted(object sender, AsyncCompletedEventArgs e)
        {
            client.DeleteCompleted -= client_DeleteCompleted;
            MessageBox.Show("Delete Success!");
            RoleViewModel.mode = Mode.Idle;
            var VM = new RoleViewModel();
        }
    }
}